#include "GraphExploration.hpp"

//----------------------------------------------------------------
GraphExploration::GraphExploration(const GraphHandler::Graph& G)
{
    m_G = &G;
    m_PG = GraphHandler::Graph();
    FillNotAdded();
}
//----------------------------------------------------------------
GraphExploration::GraphExploration(const GraphHandler::Graph& G, const GraphHandler::Graph& gPartial)
{
    // Fill everything but those which are in gPartial
    m_G = &G;
    m_PG = gPartial;
    FillNotAdded(&m_PG);
}
//----------------------------------------------------------------
void GraphExploration:: FillNotAdded(const GraphHandler::Graph* pPartial)
{
    m_kNotAdded.clear();
    m_kNotAddedEdges.clear();
    m_PGMap.clear();


    cout<< __FILE__ << ":" << __LINE__ << endl;


    // Copy all the vertices into a vector and random shuffle them

    GraphHandler::Iter_t Ibegin, Iend; tie(Ibegin, Iend) = vertices(*m_G);
    m_kNotAdded.resize(num_vertices(*m_G));

    copy(Ibegin, Iend, m_kNotAdded.begin());

    if( pPartial == 0 )
    {
        // Add one vertex as the partial graph
        GraphHandler::Vertex V = m_kNotAdded.back();
        m_kNotAdded.pop_back();

        GraphHandler::Vertex VNew = add_vertex(m_PG);
        put(vertex_name, m_PG, VNew, get(vertex_name, *m_G, V));
        //m_PGMap[V] = VNew;
        m_PGMap[V] = VNew;
    }



    cout<< __FILE__ << ":" << __LINE__ << endl;

    // If pPartial != 0, we should remove those vertices which are in pPartial
    // from m_kNotAdded
    // -----------------
    if( pPartial != 0 )
    {
        for( tie(Ibegin, Iend) = vertices(*pPartial); Ibegin != Iend; ++Ibegin )
        {
            int iVID = get(vertex_name, *pPartial, *Ibegin);
            GraphHandler::Vertex vRemove = GraphHandler::Instance().FindVertex(iVID, *m_G).second;
            m_PGMap[vRemove] = *Ibegin;
            m_kNotAdded.erase(find(m_kNotAdded.begin(), m_kNotAdded.end(), vRemove));
        }
    }
    // ------------------


    random_shuffle( m_kNotAdded.begin(), m_kNotAdded.end() );
    //---

    // Copy all the edges into a vector and random shuffle them

    graph_traits<GraphHandler::Graph>::edge_iterator firstE, lastE;
    tie(firstE, lastE) = edges(*m_G);

    m_kNotAddedEdges.resize(num_edges(*m_G));
    copy(firstE, lastE, m_kNotAddedEdges.begin());

    // If pPartial != 0, we should remove those edges which are in pPartial
    // from m_kNotAddedEdges
    // -----------------
    if( pPartial != 0 )
    {
        graph_traits<GraphHandler::Graph>::edge_iterator firstE, lastE;
        for (tie(firstE, lastE) = edges(*pPartial); firstE != lastE; ++firstE)
        {
            //remove_edge(u, v, G);
            int iVuID = get(vertex_name, *pPartial,source(*firstE, *pPartial));
            int iVvID = get(vertex_name, *pPartial,target(*firstE, *pPartial));
            GraphHandler::Vertex u = GraphHandler::Instance().FindVertex(iVuID, *m_G).second; //m_PGMap[source(*firstE, *pPartial)];
            GraphHandler::Vertex v = GraphHandler::Instance().FindVertex(iVvID, *m_G).second; //m_PGMap[target(*firstE, *pPartial)];
            GraphHandler::Edge E = edge(u, v, *m_G).first;
            m_kNotAddedEdges.erase(find(m_kNotAddedEdges.begin(), m_kNotAddedEdges.end(), E));
            //pPartial
        }
    }
    // -----------------

    random_shuffle( m_kNotAddedEdges.begin(), m_kNotAddedEdges.end() );
    //---
}
//----------------------------------------------------------------
GraphExploration::EditOpIterator::EditOpIterator(GraphExploration& GE)
{
    iEOpsLeft = -1;
    iVOpsLeft = -1;
    m_GE = &GE;
    m_G = GE.m_G;
    m_kNotAdded = GE.m_kNotAdded;
    m_kNotAddedEdges = GE.m_kNotAddedEdges;
    m_LastOp = make_pair(false, false);
}
//----------------------------------------------------------------
// Returns a pair where the first component is the ID of the vertex already existing in the partial graph
// while the second component gives the new vertex ID
pair<GraphHandler::Vertex, GraphHandler::Vertex> GraphExploration::EditOpIterator::NextVertexOp(bool bForceAdd)
{
    // Retreive a vertex not yet added, and which is possible to add at this stage

    if(iVOpsLeft == 0)
        return make_pair(GraphHandler::Vertex(), GraphHandler::Vertex());

    for(unsigned int i=0; i < m_kNotAdded.size(); i++)
    {
        // Check if this vertex is addable at this time.
        // This means that there is some edge in the example graph between some already added vertex
        // in the partial graph (so we don't get disconnected parts).

        GraphHandler::Vertex VAdd;
        VAdd = m_kNotAdded[i];

        bool bValid = false;

        graph_traits<GraphHandler::Graph>::out_edge_iterator firstE, lastE;
        GraphHandler::Vertex vAlreadyExistV;
        GraphHandler::Edge kToRemove;

        for (tie(firstE, lastE) = out_edges(VAdd, *m_G); firstE != lastE; ++firstE)
        {
            if( source(*firstE,*m_G) == VAdd )
            {
                // So the target must be a vertex already existing
                if( m_GE->m_PGMap.find(target(*firstE,*m_G)) != m_GE->m_PGMap.end() )
                {
                    bValid = true;
                    vAlreadyExistV = m_GE->m_PGMap[target(*firstE,*m_G)];
                    kToRemove = *firstE;
                    break;
                }
            }
        }

        // Force add is used to add the first vertex for instance
        if( bForceAdd || bValid )
        {

            // Add a new vertex to the partial graph and copy all the data from the example graph
            //GraphHandler::Vertex V = add_vertex(m_GE.m_PG);
            //put(vertex_name, m_GE.m_PG, V, get(vertex_name, *m_G, VAdd));

            // Connect it as well using the edge we found
            if( bValid )
            {

               // add_edge(V, vAlreadyExistV, m_GE->m_PG);
                m_kNotAddedEdges.erase(find( m_kNotAddedEdges.begin(), m_kNotAddedEdges.end(), kToRemove));

                //cout << "Adding new vertex " << m_kPartialG[V].sName << " connected from " << m_kPartialG[vAlreadyExistV].sName << endl;
            }

            // Save the correspondence vertex of m_pEGraph -> vertex of partial graph
           // m_GE->m_PGMap[VAdd] = V;

            // Remove it from m_kNotAdded
            m_kNotAdded.erase(m_kNotAdded.begin()+i);

            // Save vAlreadyExistV, vAdd incase we want to perform this edit operation
            m_LastVOp = make_pair(vAlreadyExistV, VAdd);
            m_LastOp = make_pair(true, false);

            iVOpsLeft--;
            return make_pair(get(vertex_name, m_GE->m_PG, vAlreadyExistV), get(vertex_name, *m_G, VAdd));
        }
    }

    m_LastOp = make_pair(false, false);
    return make_pair(0,0);
}
//----------------------------------------------------------------
// Performs the actual edit operation
GraphExploration& GraphExploration::EditOpIterator::operator*()
{
    if(m_LastOp.first == true && m_LastOp.second == false)
    {
        // Perform a vertex operation
        GraphHandler::Vertex V = add_vertex(m_GE->m_PG);
        put(vertex_name, m_GE->m_PG, V, get(vertex_name, *m_G, m_LastVOp.second));
        // Save the correspondence vertex of m_pEGraph -> vertex of partial graph
        // m_PGMap[VAdd] = V;
        m_GE->m_PGMap[m_LastVOp.second] = V;

        //add_edge(V, vAlreadyExistV, m_GE->m_PG);
        add_edge(V, m_LastVOp.first, m_GE->m_PG);
    }
    else if( m_LastOp.first == false && m_LastOp.second == true )
    {
        // Perform the edge operation
        //add_edge(m_PGMap[vS], m_PGMap[vT], m_kPartialG);
        add_edge(m_LastEOp.first, m_LastEOp.second, m_GE->m_PG);
    }
    else
        return *m_GE;

    m_GE->FillNotAdded(&m_GE->m_PG);
    EditOpIterator(m_GE);

    return *m_GE;
}
//----------------------------------------------------------------
// Returns how many vertex operations there are left to perform
int GraphExploration::EditOpIterator::VertexOperations()
{
    if( iVOpsLeft == -1 )
    {
    int n = 0;
    for(unsigned int i=0; i < m_kNotAdded.size(); i++)
    {
        bool bValid = false;
        GraphHandler::Vertex VAdd = m_kNotAdded[i];

        graph_traits<GraphHandler::Graph>::out_edge_iterator firstE, lastE;
        for (tie(firstE, lastE) = out_edges(VAdd, *m_G); firstE != lastE; ++firstE)
            if( source(*firstE,*m_G) == VAdd )
                // So the target must be a vertex already existing
                if( m_GE->m_PGMap.find(target(*firstE,*m_G)) != m_GE->m_PGMap.end() )
                {
                    bValid = true;
                    break;
                }

        if( bValid )
            n++;
    }
    iVOpsLeft = n;
    }

    return iVOpsLeft;
}
//----------------------------------------------------------------
bool GraphExploration::EditOpIterator::isDoneVertex()
{
    return (VertexOperations() == 0);
}
//----------------------------------------------------------------
pair<unsigned int, unsigned int> GraphExploration::EditOpIterator::NextEdgeOp()
{

    if( iEOpsLeft == 0 )
        return make_pair(0, 0);

    for(unsigned int i=0; i < m_kNotAddedEdges.size(); i++)
    {
        GraphHandler::Edge E = m_kNotAddedEdges[i];
        GraphHandler::Vertex vS = source(E, *m_G);
        GraphHandler::Vertex vT = target(E, *m_G);

        // If both vertices of the edge exist
        if( m_GE->m_PGMap.find(vS) != m_GE->m_PGMap.end() && m_GE->m_PGMap.find(vT) != m_GE->m_PGMap.end() )
        {
            //add_edge(m_PGMap[vS], m_PGMap[vT], m_kPartialG);
            // Save these incase we want to instantiate this edit op
            m_LastEOp = make_pair(m_GE->m_PGMap[vS], m_GE->m_PGMap[vT]);
            m_LastOp = make_pair(false, true);

            m_kNotAddedEdges.erase(m_kNotAddedEdges.begin()+i);
            iEOpsLeft--;
            return make_pair(get(vertex_name, *m_G, vS), get(vertex_name, *m_G, vT));
        }
    }
}
//----------------------------------------------------------------
int GraphExploration::EditOpIterator::EdgeOperations()
{
    if( iEOpsLeft == -1 )
    {
        iEOpsLeft = 0;
        for(unsigned int i=0; i < m_kNotAddedEdges.size(); i++)
        {
            GraphHandler::Edge E = m_kNotAddedEdges[i];
            GraphHandler::Vertex vS = source(E, *m_G);
            GraphHandler::Vertex vT = target(E, *m_G);

            // If both vertices of the edge exist, it is a possible edge addition
            if( m_GE->m_PGMap.find(vS) != m_GE->m_PGMap.end() && m_GE->m_PGMap.find(vT) != m_GE->m_PGMap.end() )
                iEOpsLeft++;
        }
    }

    return iEOpsLeft;
}
//----------------------------------------------------------------
bool GraphExploration::EditOpIterator::isDoneEdge()
{
    return (EdgeOperations() == 0);
}
//----------------------------------------------------------------

